package com.jieli.bt.att.util;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.ParcelUuid;
import android.text.TextUtils;

import com.jieli.logcat.JL_Log;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;

/**
 * 蓝牙工具类
 */
public class BluetoothUtil {
    private final static String TAG = BluetoothUtil.class.getSimpleName();
    private final static char[] mChars = "0123456789ABCDEF".toCharArray();

    /***
     *
     * 功能：判断手机蓝牙是否具有ble功能
     * 参数：无
     */
    public static boolean hasBle(Context context) {
        return null != context && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
    }

    /**
     * 获取设备名
     *
     * @param device BluetoothDevice 设备类型
     * @return String 设备名
     */
    @SuppressLint("MissingPermission")
    public static String getDeviceName(BluetoothDevice device, boolean isShowAddress) {
        if (null == device) return "N/A";
        String name = device.getName();
        if (null == name || name.isEmpty()) {
            if (isShowAddress) {
                return device.getAddress();
            }
            return "N/A";
        }
        return name;
    }

    public static String getDeviceName(BluetoothDevice device) {
        return getDeviceName(device, true);
    }

    /**
     * 通过蓝牙地址获取蓝牙设备对象
     *
     * @param address 蓝牙设备的地址
     * @return 蓝牙设备的对象 若操作失败，返回null.
     */
    public static BluetoothDevice getRemoteDevice(String address) {
        if (!CHexConver.checkBluetoothAddress(address)) return null;
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) return null;
        try {
            return mBluetoothAdapter.getRemoteDevice(address);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断两个蓝牙是否相等
     *
     * @param device1 BluetoothDevice实例
     * @param device2 BluetoothDevice实例
     */
    public static boolean deviceEquals(BluetoothDevice device1,
                                       BluetoothDevice device2) {
        return (device1 != null && device2 != null && device1.getAddress().equals(device2.getAddress()));
    }

    /**
     * 获取蓝牙适配器的连接状态
     *
     * @param bluetoothAdapter 蓝牙适配器对象
     * @return 连接状态
     */
    @SuppressLint({"DiscouragedPrivateApi", "MissingPermission"})
    public static int getBtAdapterConnectionState(Context context, BluetoothAdapter bluetoothAdapter) {
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) return -1;
        int state = -1;
        if (bluetoothAdapter != null) {
            try {
                Class<?> clazz = bluetoothAdapter.getClass();
                Method method = clazz.getDeclaredMethod("getConnectionState");
                //打开权限
                method.setAccessible(true);
                Object obj = method.invoke(bluetoothAdapter);
                if (!(obj instanceof Integer)) return -1;
                state = (int) obj;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//        JL_Log.d(TAG, "BluetoothAdapter state : " + state);
        return state;
    }

    /**
     * 检查指定的蓝牙设备是否已连接
     *
     * @param device 蓝牙设备
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean isBTConnected(Context context, BluetoothDevice device) {
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) return false;
        boolean isConnected = false;
        if (device != null) {
            try {
                Class<?> clazz = device.getClass();
                Method isConnectedMethod = clazz.getDeclaredMethod("isConnected");
                Object obj = isConnectedMethod.invoke(device);
                if (!(obj instanceof Boolean)) return false;
                isConnected = (boolean) obj;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return isConnected;
    }

    /**
     * 获取系统已连接的蓝牙设备列表
     */
    @SuppressLint("MissingPermission")
    public static List<BluetoothDevice> getSystemConnectedBtDeviceList(Context context) {
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) {
            JL_Log.i(TAG, "getSystemConnectedBtDeviceList", "no connect permission.");
            return new ArrayList<>();
        }
        List<BluetoothDevice> mSystemConnectedList = new ArrayList<>();
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        try {//得到连接状态的方法
            int state = getBtAdapterConnectionState(context, adapter);
            JL_Log.i(TAG, "getSystemConnectedBtDeviceList", "state : " + state);
            if (state == BluetoothAdapter.STATE_CONNECTED || state == BluetoothAdapter.STATE_DISCONNECTED) {
                Set<BluetoothDevice> devices = adapter.getBondedDevices();
                JL_Log.i(TAG, "getSystemConnectedBtDeviceList", "devices : " + devices.size());
                //筛选已配对的设备列表
                for (BluetoothDevice device : devices) {
                    boolean isConnected = isBTConnected(context, device);
//                    JL_Log.i(TAG, "-getSystemConnectedBtDeviceList- bound device:" + printBtDeviceInfo(device) + ", isConnected : " + isConnected);
                    if (isConnected) {
                        mSystemConnectedList.add(device);
                    }
                }
            }
            //部分手机会因为查询GATT的设备连接列表而ANR，弃用
            /*BluetoothManager mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager != null) {
                List<BluetoothDevice> mConnectList = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
                //筛选已连接的设备列表
                if (mConnectList != null) {
                    for (BluetoothDevice device : mConnectList) {
                        JL_Log.d(TAG, "-getSystemConnectedBtDeviceList- connect device:" + printBtDeviceInfo(context, device));
                        if (!mSystemConnectedList.contains(device)) {
                            JL_Log.i(TAG, "-getSystemConnectedBtDeviceList- add list");
                            mSystemConnectedList.add(device);
                        }
                    }
                }
            }*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!mSystemConnectedList.isEmpty()) {
            return mSystemConnectedList;
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 16进制数据包转换成地址格式
     *
     * @param data 16进制数据包
     * @return 蓝牙地址
     */
    public static String hexDataCovetToAddress(byte[] data) {
        StringBuilder sb = new StringBuilder();
        if (data != null && data.length == 6) {
            for (int n = 0; n < data.length; n++) {
                sb.append(mChars[(data[n] & 0xFF) >> 4]);
                sb.append(mChars[data[n] & 0x0F]);
                if (n != (data.length - 1)) {
                    sb.append(":");
                }
            }
        }
        return sb.toString();
    }

    /**
     * 16进制字符串转换成16进制数组
     *
     * @param hexString 16进制字符串
     * @return 16进制数组
     */
    public static byte[] hexStringCovertToByteArray(String hexString) {
        byte[] addrBuf = null;
        if (!TextUtils.isEmpty(hexString)) {
            addrBuf = new byte[hexString.length() / 2];
            for (int i = 0; i < addrBuf.length; i++) {
                int index = i * 2;
                if (index + 2 <= hexString.length()) {
                    try {
                        int value = Integer.valueOf(hexString.substring(index, index + 2), 16);
                        addrBuf[i] = (byte) value;
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            }
        }
        return addrBuf;
    }

    /**
     * 反转地址
     *
     * @param srcAddr 原地址
     * @return 反转后的地址
     */
    public static String reverseAddressString(String srcAddr) {
        if (!CHexConver.checkBluetoothAddress(srcAddr)) return srcAddr;
        if (srcAddr.contains(":")) {
            srcAddr = srcAddr.replaceAll(":", "");
        }
        byte[] address = hexStringCovertToByteArray(srcAddr);
        if (address == null) return srcAddr;
        byte[] addressReverse = new byte[6];
        for (int i = 0, j = address.length - 1; i < address.length & j >= 0; i++, j--) {
            addressReverse[i] = address[j];
        }
        return hexDataCovetToAddress(addressReverse);
    }


    @SuppressLint("MissingPermission")
    public static String printBtDeviceInfo(Context context, BluetoothDevice device) {
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) return "null";
        String content;
        if (device != null) {
            content = "name : " + device.getName() + " ,type : " + device.getType() + " ,address : " + device.getAddress();
        } else {
            content = "null";
        }
        return content;
    }

    /**
     * 蓝牙地址转换成16进制数据包
     *
     * @param address 蓝牙地址
     * @return 16进制数据包
     */
    public static byte[] addressCovertToByteArray(String address) {
        byte[] addrBuf = null;
        if (!TextUtils.isEmpty(address) && address.contains(":")) {
            String hexString = address.replace(":", "");
            addrBuf = new byte[hexString.length() / 2];
            if (addrBuf.length == 6) { //地址符合规范
                for (int i = 0; i < addrBuf.length; i++) {
                    int index = i * 2;
                    if (index + 2 <= hexString.length()) {
                        try {
                            int value = Integer.valueOf(hexString.substring(index, index + 2), 16);
                            addrBuf[i] = (byte) value;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return null;
                        }
                    }
                }
            } else {
                addrBuf = null;
            }
        }
        return addrBuf;
    }

    /**
     * 判断手机蓝牙是否打开
     *
     * @return 若为true，蓝牙模块打开; 若为false，蓝牙模块关闭
     */
    @SuppressLint("MissingPermission")
    public static boolean isBluetoothEnable() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        return adapter != null && adapter.isEnabled();
    }

    /**
     * 进行蓝牙设备绑定操作
     *
     * @param device    蓝牙设备
     * @param transport 协议类型
     * @return 操作结果
     */
    @SuppressLint("MissingPermission")
    public static boolean createBond(Context context, BluetoothDevice device, int transport) {
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) return false;
        boolean bRet = false;
        try {
            Class<BluetoothDevice> bluetoothDeviceClass = BluetoothDevice.class;
            Class<?>[] args = new Class[1];
            args[0] = int.class;
            Method createBondMethod = bluetoothDeviceClass.getDeclaredMethod("createBond", args);
            createBondMethod.setAccessible(true);
            Object obj = createBondMethod.invoke(device, transport);
            if (!(obj instanceof Boolean)) return false;
            bRet = (boolean) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bRet;
    }

    /**
     * 设备配对方法
     *
     * @param device 设备对象
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean createBond(Context context, BluetoothDevice device) {
        if (device == null || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        boolean bRet = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            bRet = device.createBond();
        } else {
            Class<?> btClass = device.getClass();
            try {
                Method createBondMethod = btClass.getMethod("createBond");
                Object obj = createBondMethod.invoke(device);
                if (!(obj instanceof Boolean)) return false;
                bRet = (boolean) obj;
            } catch (Exception e) {
                e.printStackTrace();
                JL_Log.e(TAG, "createBond", "Invoke createBond : " + e.getMessage());
            }
        }
        return bRet;
    }

    /**
     * 设备取消配对方法
     *
     * @param device 设备对象
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean removeBond(Context context, BluetoothDevice device) {
        if (device == null || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        boolean bRet = false;
        Class<?> btClass = device.getClass();
        try {
            Method removeBondMethod = btClass.getMethod("removeBond");
            Object object = removeBondMethod.invoke(device);
            if (!(object instanceof Boolean)) return false;
            bRet = (boolean) object;
        } catch (Exception e) {
            e.printStackTrace();
            JL_Log.e(TAG, "removeBond", "Invoke removeBond : " + e.getMessage());
        }
        return bRet;
    }

    /**
     * 判断设备是否拥有服务
     *
     * @param device      蓝牙设备
     * @param profileUuid 服务UUID
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean deviceHasProfile(Context context, BluetoothDevice device, UUID profileUuid) {
        if (!isBluetoothEnable() || null == device || null == profileUuid || TextUtils.isEmpty(profileUuid.toString())) {
            return false;
        }
        if (!PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context)) return false;
        boolean ret = false;
        ParcelUuid[] uuids = device.getUuids();
        if (null == uuids) return false;
        for (ParcelUuid uuid : uuids) {
            if (uuid == null) continue;
            if (profileUuid.toString().equalsIgnoreCase(uuid.toString())) {
                ret = true;
                break;
            }
        }
        return ret;
    }

    /**
     * 反射系统函数
     *
     * @return 系统函数
     */
    public static Method getDeclaredMethod() throws Exception {
        return Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
    }

    /**
     * 设置经典蓝牙设备的优先级
     *
     * @param profile  经典蓝牙协议对象（A2DP或HFP）
     * @param device   蓝牙设备对象
     * @param priority 优先级(ON -- 100 or OFF --- 0)
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean setPriority(Context context, BluetoothProfile profile, BluetoothDevice device, int priority) {
        if (profile == null || device == null || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        try {
            Method getDeclaredMethod = getDeclaredMethod();
            Method setPriorityMethod = (Method) getDeclaredMethod.invoke(profile.getClass(), "setPriority", new Class[]{BluetoothDevice.class, int.class});
            if (setPriorityMethod == null) return false;
            Object obj = setPriorityMethod.invoke(profile, device, priority);
            if (!(obj instanceof Boolean)) return false;
            return (boolean) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取经典蓝牙设备的优先级
     *
     * @param profile 经典蓝牙协议对象（A2DP或HFP）
     * @param device  蓝牙设备对象
     * @return 优先级
     */
    @SuppressLint("MissingPermission")
    public static int getPriority(Context context, BluetoothProfile profile, BluetoothDevice device) {
        if (profile == null || device == null || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return 0;
        try {
            Method getDeclaredMethod = getDeclaredMethod();
            Method getPriorityMethod = (Method) getDeclaredMethod.invoke(profile.getClass(), "getPriority", new Class[]{BluetoothDevice.class});
            if (getPriorityMethod == null) return 0;
            Object obj = getPriorityMethod.invoke(profile, device);
            if (!(obj instanceof Integer)) return 0;
            return (int) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 连接蓝牙设备的A2DP服务
     *
     * @param bluetoothA2dp 蓝牙A2DP服务对象
     * @param device        蓝牙设备
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean connectDeviceA2dp(Context context, BluetoothA2dp bluetoothA2dp, BluetoothDevice device) {
        if (null == bluetoothA2dp || null == device || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        Class<?> btClass = bluetoothA2dp.getClass();
        boolean ret = false;
        try {
            Method connect = btClass.getMethod("connect", BluetoothDevice.class);
            Object obj = connect.invoke(bluetoothA2dp, device);
            if (!(obj instanceof Boolean)) return false;
            ret = (boolean) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 断开设备的A2DP服务
     *
     * @param bluetoothA2dp A2DP服务对象
     * @param device        蓝牙设备
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean disconnectDeviceA2dp(Context context, BluetoothA2dp bluetoothA2dp, BluetoothDevice device) {
        if (null == bluetoothA2dp || null == device || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        boolean ret = false;
        try {
            Class<?> btClass = bluetoothA2dp.getClass();
            Method disconnect = btClass.getMethod("disconnect", BluetoothDevice.class);
            disconnect.setAccessible(true);
            Object obj = disconnect.invoke(bluetoothA2dp, device);
            if (!(obj instanceof Boolean)) return false;
            ret = (boolean) obj;
        } catch (Exception e) {
            JL_Log.e(TAG, "disconnectDeviceA2dp", "have an exception : " + e);
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 连接蓝牙设备的HFP服务
     *
     * @param bluetoothHeadset 蓝牙HFP服务对象
     * @param device           蓝牙设备
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean connectDeviceHfp(Context context, BluetoothHeadset bluetoothHeadset, BluetoothDevice device) {
        if (null == bluetoothHeadset || null == device || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        boolean ret = false;
        Class<?> btClass = bluetoothHeadset.getClass();
        try {
            Method connect = btClass.getMethod("connect", BluetoothDevice.class);
            connect.setAccessible(true);
            Object obj = connect.invoke(bluetoothHeadset, device);
            if (!(obj instanceof Boolean)) return false;
            ret = (boolean) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 断开设备的HFP服务
     *
     * @param bluetoothHeadset HFP服务对象
     * @param device           蓝牙设备
     * @return 结果
     */
    @SuppressLint("MissingPermission")
    public static boolean disconnectDeviceHfp(Context context, BluetoothHeadset bluetoothHeadset, BluetoothDevice device) {
        if (null == bluetoothHeadset || null == device || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return false;
        boolean ret = false;
        try {
            Class<?> btClass = bluetoothHeadset.getClass();
            Method disconnect = btClass.getMethod("disconnect", BluetoothDevice.class);
            disconnect.setAccessible(true);
            Object obj = disconnect.invoke(bluetoothHeadset, device);
            if (!(obj instanceof Boolean)) return false;
            ret = (boolean) obj;
        } catch (Exception e) {
            JL_Log.e(TAG, "disconnectFromHfp", "have an exception : " + e);
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * 国际化处理String格式
     *
     * @param format 格式
     * @param args   参数
     * @return 字符串
     */
    public static String formatString(String format, Object... args) {
        return String.format(Locale.ENGLISH, format, args);
    }

    /**
     * 打印BLE的GATT服务信息
     *
     * @param device BLE设备
     * @param gatt   GATT管理对象
     * @param status 状态
     */
    @SuppressLint("MissingPermission")
    public static String printBleGattServices(Context context, BluetoothDevice device, BluetoothGatt gatt, int status) {
        if (device == null || gatt == null || !PermissionUtil.INSTANCE.hasBluetoothConnectPermission(context))
            return "";
        StringBuilder builder = new StringBuilder(formatString("\n[[====\tBluetooth[%s], status[%d]\t====]]\n",
                printBtDeviceInfo(context, device), status));
        List<BluetoothGattService> services = gatt.getServices();
        if (null != services) {
            builder.append(formatString("[[====\tService Size: [%d]\t====]]\n", services.size()));
            for (BluetoothGattService service : services) {
                if (null == service) continue;
                builder.append(formatString("[[====\tService: [%s]\t====]]\n", UuidUtil.read16BitUUID(service.getUuid())));
                List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
                if (null == characteristics) continue;
                builder.append(formatString("[[[[====\tCharacteristics Size: [%d]\t====]]]]\n", characteristics.size()));
                for (BluetoothGattCharacteristic characteristic : characteristics) {
                    if (null == characteristic) continue;
                    builder.append(formatString("[[[[====\tCharacteristic: [%s], %s\t====]]]]\n",
                            UuidUtil.read16BitUUID(characteristic.getUuid()), getPropertiesString(characteristic.getProperties())));
                    List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
                    if (null == descriptors) continue;
                    builder.append(formatString("[[[[[[====\tDescriptors Size: [%d]\t====]]]]]]\n", descriptors.size()));
                    for (BluetoothGattDescriptor descriptor : descriptors) {
                        if (null == descriptor) continue;
                        builder.append(formatString("[[[[[[====\tDescriptor: [%s], value : [%s]\t====]]]]]]\n",
                                UuidUtil.read16BitUUID(descriptor.getUuid()), CHexConver.byte2HexStr(descriptor.getValue())));
                    }
                }
            }
        }
        builder.append(formatString("[[====\tBluetooth[%s] Services show End\t====]]", printBtDeviceInfo(context, device)));
        return builder.toString();
    }

    public static String printBoundState(int state) {
        switch (state) {
            case BluetoothDevice.BOND_NONE:
                return "BOND_NONE(10)";
            case BluetoothDevice.BOND_BONDING:
                return "BOND_BONDING(11)";
            case BluetoothDevice.BOND_BONDED:
                return "BOND_BONDED(12)";
            default:
                return formatString("UNKNOWN_BOUND_STATE(%d)", state);
        }
    }

    public static String printConnectionState(int state) {
        switch (state) {
            case BluetoothProfile.STATE_CONNECTING:
                return "STATE_CONNECTING(1)";
            case BluetoothProfile.STATE_CONNECTED:
                return "STATE_CONNECTED(2)";
            case BluetoothProfile.STATE_DISCONNECTED:
                return "STATE_DISCONNECTED(0)";
            default:
                return formatString("UNKNOWN_CONNECTION(%d)", state);
        }
    }

    private static boolean checkExistProperty(int properties, int property) {
        return (properties & property) == property;
    }

    private static String getPropertiesString(int properties) {
        StringBuilder stringBuilder = new StringBuilder();
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_BROADCAST)) {
            stringBuilder.append("BROADCAST");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_READ)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("READ");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("WRITE NO RESPONSE");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_WRITE)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("WRITE");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_NOTIFY)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("NOTIFY");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_INDICATE)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("INDICATE");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("SIGNED WRITE");
        }
        if (checkExistProperty(properties, BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS)) {
            if (stringBuilder.length() > 0) {
                stringBuilder.append(", ");
            }
            stringBuilder.append("EXTENDED PROPS");
        }
        return stringBuilder.toString();
    }

}
